package ch.ti.bfh.app.loodel.domain.learningEvent;

import ch.ti.bfh.app.loodel.domain.member.Member;
import ch.ti.bfh.app.loodel.domain.timeslot.TimeSlot;
import ch.ti.bfh.app.loodel.service.admin.LearningEventAdministrationException;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import org.hibernate.validator.constraints.NotBlank;
import org.joda.time.DateTime;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

@Entity
public class LearningEvent {

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    private String id;

    @ManyToOne
    @NotNull
    private Member owner;

    @NotBlank
    private String groupName;

    @NotBlank
    private String modulName;

    @OneToMany(mappedBy = "learningEvent")
    @Size(min = 1, message = "At least one TimeSlot needs to be defined")
    @OrderBy("startDateTime, id")
    private Set<TimeSlot> timeSlots = new HashSet<TimeSlot>();

    private String description;

    @NotNull
    private boolean votesClosed = false;

    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    private DateTime createTime;

    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    private DateTime lastUpdatedTime;

    public LearningEvent(Member owner, String groupName, String modulName, Set<TimeSlot> timeSlots) {
        this.owner = owner;
        this.groupName = groupName;
        this.modulName = modulName;
        this.timeSlots = timeSlots;
        this.votesClosed = false;
    }

    public LearningEvent() {
    }

    @PreUpdate
    @PrePersist
    public void updateTimeStamps() {
        lastUpdatedTime = new DateTime();
        if (createTime == null) {
            createTime = new DateTime();
        }
    }


    public boolean isAtLeastOneTimeSlotAccepted() {
        for (TimeSlot timeSlot : this.getTimeSlots()) {
            if (timeSlot.getTakingPlace()) {
                return true;
            }
        }
        return false;
    }

    public void closeLearningEventVotes() throws LearningEventAdministrationException {
        if (isAtLeastOneTimeSlotAccepted()) {
            this.votesClosed = true;
        } else {
            throw new LearningEventAdministrationException("Before you close the LearningEvent you need to approve at least one Time Slot", id);
        }
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String comment) {
        this.description = comment;
    }

    public String getId() {
        return id;
    }

    public String getGroupName() {
        return groupName;
    }

    public String getModulName() {
        return modulName;
    }

    public Member getOwner() {
        return owner;
    }

    public Boolean getVotesClosed() {
        return votesClosed;
    }

    public Set<TimeSlot> getTimeSlots() {
        return Collections.unmodifiableSet(this.timeSlots);
    }

    public DateTime getCreateTime() {
        return createTime;
    }

    public String getTitle() {
        return "Module: " + this.getModulName() + " Group: " + this.getGroupName();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof LearningEvent)) return false;

        LearningEvent that = (LearningEvent) o;

        if (id != null ? !id.equals(that.id) : that.id != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }

    public void rejectAllTimeSlots() {
        for (TimeSlot timeSlot : timeSlots) {
            timeSlot.setTakingPlace(false);
        }
    }
}
